﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;

namespace TaskSyncOperation
{
    internal class TaskRunner
    {
        internal static TaskRunner Instance { get; } = new TaskRunner();

        private TaskRunner() { }

        // 存储任务工厂（延迟执行）
        private readonly ConcurrentDictionary<string, Func<Task>> _taskFactories = new();

        /// <summary>
        /// 注册可执行任务工厂
        /// </summary>
        /// <param name="target">ID</param>
        /// <param name="taskFactory">任务的执行逻辑</param>
        /// <exception cref="ArgumentException">不能为空</exception>
        internal void AddTask(string target, Func<Task> taskFactory)
        {
            if (string.IsNullOrWhiteSpace(target) || taskFactory == null)
                throw new ArgumentException("id and task factory cannot be null or empty.");
            // 添加或更新任务工厂
            _taskFactories.AddOrUpdate(target, taskFactory, (key, oldValue) => taskFactory);
        }

        /// <summary>
        /// 启动任务并等待全部任务完成，支持超时
        /// </summary>
        /// <param name="targets">目标ID列表</param>
        /// <param name="millisecondsTimeout">超时时间</param>
        /// <returns>完成的任务数量，超时返回-1</returns>
        internal async Task<int> WaitAllTasks(IEnumerable<string> targets, int millisecondsTimeout)
        {
            var selected = _taskFactories
                .Where(kvp => targets.Contains(kvp.Key, StringComparer.OrdinalIgnoreCase))
                .ToDictionary(kvp => kvp.Key, kvp => kvp.Value);

            if (selected.Count == 0)
                return -1;

            // 启动所有任务
            Dictionary<string, Task> runningTasks = new();
            foreach (var kv in selected)
            {
                try
                {
                    runningTasks[kv.Key] = kv.Value.Invoke();
                }
                catch
                {
                    // 任务创建异常可记录日志
                }
            }

            var all = Task.WhenAll(runningTasks.Values);
            var timeoutTask = Task.Delay(millisecondsTimeout);

            var completed = await Task.WhenAny(all, timeoutTask);

            // 清除任务
            foreach (var key in runningTasks.Keys)
                _taskFactories.TryRemove(key, out _);

            return (completed == all) ? runningTasks.Count : -1;
        }

        /// <summary>
        /// 执行并等待任意一个任务完成，支持超时
        /// </summary>
        /// <param name="targets">目标ID列表</param>
        /// <param name="millisecondsTimeout">超时时间</param>
        /// <returns>超时返回-1</returns>
        internal async Task<int> WaitAnyTask(IEnumerable<string> targets, int millisecondsTimeout)
        {
            var selected = _taskFactories
                .Where(kvp => targets.Contains(kvp.Key, StringComparer.OrdinalIgnoreCase))
                .ToDictionary(kvp => kvp.Key, kvp => kvp.Value);

            if (selected.Count == 0)
                return -1;

            var keys = selected.Keys.ToList();
            var tasks = selected.Values.Select(factory => factory.Invoke()).ToArray();

            var timeoutTask = Task.Delay(millisecondsTimeout);
            var completedTask = await Task.WhenAny(Task.WhenAny(tasks), timeoutTask);

            foreach (var key in keys)
                _taskFactories.TryRemove(key, out _);

            return (completedTask == timeoutTask) ? -1 : Array.IndexOf(tasks, ((Task<Task>)completedTask).Result);
        }
    }
}
